package org.familysearch.fsapi.gwt.server.dao.rest;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.familysearch.fsapi.gwt.common.Logger;
import org.familysearch.fsapi.gwt.common.client.entities.Temple;
import org.familysearch.fsapi.gwt.server.dao.DAOException;
import org.familysearch.fsapi.gwt.server.dao.TempleDAO;
import org.familysearch.fsapi.gwt.server.dao.rest.parsers.TempleSAXParser;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.google.gwt.i18n.client.DateTimeFormat;

public class TempleDAOREST
		extends GenericRESTDAO<Temple, String>
		implements TempleDAO
{

	private Logger log;
	private static DateTimeFormat dateTime;
	
	public TempleDAOREST()
	{
		log = Logger.getLogger(this.getClass().getName());
	}
	
	public List<Temple> findAll(boolean ascending) throws DAOException {
		// TODO get all of the temples with ASC (ie, reverse the order as default is DESC)
		return null;
	}

	public List<Temple> findAll(int maxResults, boolean ascending) throws DAOException {
		// TODO get all of the temples, truncate list to maxResults
		return null;
	}

	public List<Temple> findAll(String sortBy, boolean ascending) throws DAOException {
		// TODO get all of the temples with ASC by 'sortBy'
		return null;
	}

	public List<Temple> findAll(int maxResults, String sortBy, boolean ascending) throws DAOException {
		// TODO get all of the temples, truncate list to maxResults with ASC by 'sortBy'
		return null;
	}

	public List<Temple> findAll() throws DAOException {

		ArrayList<Temple> temples = null;
		TempleSAXParser parser = new TempleSAXParser();
		
		if( session == null )
		{
			throw new DAOException("DAO-0002", "No valid session. Please authenticate first.");
		}
		
		/*
		 * Use the sessionId and temple code to fetch info about the temple
		 */
		String url = "http://www.dev.usys.org/temple/v1/temple";
		url += "?sessionId=" + this.getSession().getId();
		
		// refresh the client
		client = new HttpClient();
		
		// use the get method
		GetMethod method = new GetMethod(url);
		try {
			client.executeMethod(method);
		} catch (HttpException e) {
			// TODO swallow HttpException and throw a DAOException
			e.printStackTrace();
		} catch (IOException e) {
			// TODO swallow IOException and throw a DAOException
			e.printStackTrace();
		}	
		
		if( method.getStatusCode() == 200 )
		{
			InputStream responseBody = null;
			try {
				responseBody = method.getResponseBodyAsStream();
			} catch (IOException e) {
				// TODO swallow IOException and throw a DAOException
				e.printStackTrace();
			}
			
	
			// parse XML
			String xml = parseInputStream(responseBody);
			log.debug(xml);
			XPath xpath = XPathFactory.newInstance().newXPath();
			
			SAXParser sax = null;
			SAXParserFactory spf = SAXParserFactory.newInstance();

			try {
				sax = SAXParserFactory.newInstance().newSAXParser();
			} catch (ParserConfigurationException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (SAXException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			// obtain sessionID
			
			try {
				InputSource source = new InputSource(new StringReader(xml));
				sax.parse(source, parser);

			} catch (SAXException e) {
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		temples = parser.getTemples();
		
		if( temples == null )
		{
			throw new DAOException("DAO-0001", method.getStatusLine().toString() + " while trying to reach http://www.dev.usys.org" + method.getPath() + " with valid session ID.");
		}

		return temples;		
		
	}

	public List<Temple> findByExample(Temple exampleInstance, String... excludeProperty) throws DAOException {
		// TODO Given an example, search through the temples for something like it (String[] of properties is can be null)
		return null;
	}


	public Temple findById(String id) throws DAOException {
		
		/*
		 * The calling BO should always have authenticated before
		 * coming down to an entity DAO, so we know that
		 * the parent DAO class has a sessionID
		 */
		
		
		if( session == null )
		{
			throw new DAOException("DAO-0002", "No valid session. Please authenticate first.");
		}
		
		/*
		 * Use the sessionId and temple code to fetch info about the temple
		 */
		String url = "http://www.dev.usys.org/temple/v1/temple/";
		url += id;
		url += "?sessionId=" + this.getSession().getId();
		
		// refresh the client
		client = new HttpClient();
		
		// use the get method
		GetMethod method = new GetMethod(url);
		try {
			client.executeMethod(method);
		} catch (HttpException e) {
			// TODO swallow HttpException and throw a DAOException
			e.printStackTrace();
		} catch (IOException e) {
			// TODO swallow IOException and throw a DAOException
			e.printStackTrace();
		}		
		
		Temple temple = null;
		
		if( method.getStatusCode() == 200 )
		{
			InputStream responseBody = null;
			try {
				responseBody = method.getResponseBodyAsStream();
			} catch (IOException e) {
				// TODO swallow IOException and throw a DAOException
				e.printStackTrace();
			}
			
	
			// parse XML
			String xml = parseInputStream(responseBody);
			log.debug(xml);
			XPath xpath = XPathFactory.newInstance().newXPath();
			
			// obtain sessionID
			
			try {
				InputSource source = new InputSource(new StringReader(xml));
				Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(source);
				
				temple = new Temple();
				temple.setCode( id );
				
				String name = xpath.evaluate("//name", document);
				temple.setName(name);
				log.debug(name);
				
				//String location = xpath.evaluate("//location",document);
				//temple.setLocation(location);
				
				String dateString = xpath.evaluate("//dedicationDate",document);
				if( dateString != "" )
				{
					Date dedicationDate = dateTime.parse(dateString);
					temple.setDedicationDate(dedicationDate);
				}
				else
				{
					log.warn(temple.getName() + " does not have a dedication date");
				}
				
				
			} catch (XPathExpressionException e) {
				e.printStackTrace();
			} catch (SAXException e) {
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
		}
		
		if( temple == null )
		{
			throw new DAOException("DAO-0001", method.getStatusLine().toString() + " while trying to reach http://www.dev.usys.org" + method.getPath() + " with valid session ID.");
		}

		return temple;		

	}

	public List<Temple> findAll(Temple loaded) throws DAOException {
		
		/*
		 * loaded means:
		 * - findAll()
		 * - then, for each in findAll(), findById()
		 */
		ArrayList<Temple> loadedTempleList = new ArrayList<Temple>();
		ArrayList<Temple> temples = (ArrayList<Temple>) findAll();
		log.debug(temples.get(temples.size()-1));
		for (Iterator iterator = temples.iterator(); iterator.hasNext();) {
			Temple temple = (Temple) iterator.next();
			
			// now fetch specific data for this temple
			temple = findById(temple.getCode());
			loadedTempleList.add(temple);
			
		}
		
		return loadedTempleList;
	}


}
